package plugin.bpce.util;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import plugin.bpce.modelo.BPCEResult;
import plugin.bpce.modelo.ModeloAvaliado;

public class ImportaDiagramas {
	private DocumentBuilder Build;
	private DOMImplementation DOM;
	private DocumentBuilderFactory Factory;
	private Document impDiagrama;
	private Node noRaiz;
	private String PathProjeto;
	private XPath xpath;
	private Map<String, String> mapaModelosImportados;

	public ImportaDiagramas(String pathProjeto) {
		boolean Existe;
		File tmp;

		this.PathProjeto = pathProjeto;
		Existe = false;

		try {
			xpath = XPathFactory.newInstance().newXPath();
			Factory = DocumentBuilderFactory.newInstance();
			Factory.setNamespaceAware(false);
			Factory.setIgnoringComments(true);
			Build = Factory.newDocumentBuilder();
			DOM = Build.getDOMImplementation();

			tmp = new File(this.PathProjeto + "/.bpce");

			impDiagrama = Build.parse(tmp);

			noRaiz = this.impDiagrama.getDocumentElement();
			Existe = true;
		} catch (Exception e) {
			Existe = false;
		}

		if (!Existe) {
			GeraArquivo();
		}
	}

	public void apagaImportacao(List<ModeloAvaliado> modeloAvaliado) {
		Node noModelo;
		int i;
		String nomeAutor, nomeModelo;
		ModeloAvaliado modelo;

		try {		
			for (i = 0; i < modeloAvaliado.size(); i++) {
				modelo = modeloAvaliado.get(i);
				nomeModelo = modelo.getNomeModelo();
				nomeAutor = modelo.getNomeAutor();
				
				noModelo =  (Node) xpath.evaluate("//Modelo[@NomeModelo='" + nomeModelo + "' and @NomeAutor='" + nomeAutor + "']", this.noRaiz, XPathConstants.NODE);
						
				this.noRaiz.removeChild(noModelo);
			}

			GeraXML(this.impDiagrama, this.PathProjeto + "/.bpce");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("static-access")
	private Element CopiaFilhos(Node node, Document docTela) {
		Element novo, novofilho;
		NamedNodeMap att;
		int i;
		Node notmp;
		NodeList filhos;
		String texto;

		novo = docTela.createElement(node.getNodeName());

		if (node.hasAttributes()) {
			att = node.getAttributes();

			for (i = 0; i < att.getLength(); i++) {
				notmp = att.item(i);
				novo.setAttribute(notmp.getNodeName(), notmp.getTextContent());
			}
		}

		texto = node.getTextContent();
		if ((texto != "") && (texto.indexOf("\n") < 0)) {
			novo.setTextContent(texto);
		}

		try {
			filhos = (NodeList) xpath.evaluate("*", node,
					XPathConstants.NODESET);

			if (filhos.getLength() > 0) {
				for (i = 0; i < filhos.getLength(); i++) {
					novofilho = CopiaFilhos(filhos.item(i), docTela);
					novo.appendChild(novofilho);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return novo;
	}

	private void GeraArquivo() {
		try {
			this.impDiagrama = this.DOM.createDocument(null, null, null);

			noRaiz = this.impDiagrama.createElement("ModelosImportados");
			this.impDiagrama.insertBefore(noRaiz, null);

			GeraXML(this.impDiagrama, this.PathProjeto + "/.bpce");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void GeraXML(Document doc, String Caminho) {
		FileWriter writer;
		BufferedWriter buf;
		OutputFormat format;
		XMLSerializer output;

		try {
			writer = new FileWriter(Caminho);
			buf = new BufferedWriter(writer);
			format = new OutputFormat(doc, "ISO-8859-1", true);
			format.setLineSeparator(System.getProperty("line.separator"));
			output = new XMLSerializer(buf, format);
			output.serialize(doc);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("static-access")
	public String[] getNomeDiagramasImportados() {
		String NomeModelos[];		
		NodeList nlModelos;
		int i;
		Element noModelo;

		try {
			mapaModelosImportados = new HashMap<String, String>();
			nlModelos = (NodeList) xpath.evaluate("//Modelo", noRaiz, XPathConstants.NODESET);

			NomeModelos = new String[nlModelos.getLength()];

			for (i = 0; i < nlModelos.getLength(); i++) {
				noModelo = (Element) nlModelos.item(i);
				NomeModelos[i] = noModelo.getAttribute("NomeModelo");
				mapaModelosImportados.put(noModelo.getAttribute("NomeModelo"), noModelo.getAttribute("NomeAutor"));
			}

			return NomeModelos;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@SuppressWarnings("static-access")
	public void Importa(int[] linhasSelecionadas, BPCEResult[] resultadoBusca,
			File Diagrama) {
		Node noRaiz, noLastPack, noPackageImport, noDiagrama, notmp, noRaizModelo;
		int i, j;
		Document docTela, docDiagrama;
		InputStream inDiagrama;
		NamedNodeMap att;
		NodeList filhos;
		Element tmp, filho, noModelo;

		try {
			noRaiz = this.impDiagrama.getDocumentElement();

			docTela = Build.parse(Diagrama);
			noLastPack = (Node) xpath.evaluate("//packagedElement[last()]", docTela, XPathConstants.NODE);
			noPackageImport = (Node) xpath.evaluate("//packageImport", docTela, XPathConstants.NODE);

			if (noLastPack != null)
				noRaizModelo = noLastPack.getParentNode();
			else
				noRaizModelo = noPackageImport.getParentNode();

			docDiagrama = null;

			for (i = 0; i < linhasSelecionadas.length; i++) {
				noModelo = this.impDiagrama.createElement("Modelo");
				noModelo.setAttribute("NomeModelo", resultadoBusca[linhasSelecionadas[i]].getNomeDiagrama());
				noModelo.setAttribute("AgencyModelo", resultadoBusca[linhasSelecionadas[i]].getAgencyId());
				noModelo.setAttribute("NomeAutor", resultadoBusca[linhasSelecionadas[i]].getNomeAutor());

				noRaiz.appendChild(noModelo);

				inDiagrama = new ByteArrayInputStream(resultadoBusca[linhasSelecionadas[i]].getDiagrama());
				docDiagrama = Build.parse(inDiagrama);
				noDiagrama = docDiagrama.getDocumentElement();

				tmp = docTela.createElement("packagedElement");
				att = noDiagrama.getAttributes();

				for (j = 0; j < att.getLength(); j++) {
					notmp = att.item(j);
					tmp.setAttribute(notmp.getNodeName(), notmp.getTextContent());
				}

				filhos = (NodeList) xpath.evaluate("*", noDiagrama, XPathConstants.NODESET);

				for (j = 0; j < filhos.getLength(); j++) {
					filho = CopiaFilhos(filhos.item(j), docTela);
					tmp.appendChild(filho);
				}

				if (noLastPack != null)
					noRaizModelo.insertBefore(tmp, noLastPack);
				else
					noRaizModelo.insertBefore(tmp, noPackageImport);
			}

			GeraXML(this.impDiagrama, this.PathProjeto + "/.bpce");
			GeraXML(docTela, Diagrama.getAbsolutePath());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public Map<String, String> getMapaModelosImportados() {		
		return mapaModelosImportados;
	}
}